package icu.zhhll.util.json;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zh
 * @date 2023/7/25 15:49
 */
public class GsonUtils {
    private static final Gson GSON = new Gson();
    private static final Gson DEFAULT_BUILDER = new GsonBuilder().create();
    // 序列化空字段
    private static final Gson SERIALIZE_NULL = new GsonBuilder().serializeNulls().create();
    // 处理特殊的Double和Float
    private static final Gson SERIALIZE_FLOATING_POINT = new GsonBuilder().serializeSpecialFloatingPointValues().create();
    // null字符串处理为""
    private static final Gson NULL_STRING_TO_BLACK = new GsonBuilder().serializeNulls()
            .registerTypeAdapterFactory(new NullStringToBlackAdapterFactory()).create();
    // 对于html中的特殊字符不进行转义
    private static final Gson DISABLE_HTML_ESCAPING = new GsonBuilder().disableHtmlEscaping().create();

    private GsonUtils() {

    }

    public static Gson instance() {
        return GSON;
    }

    public static Gson defaultBuilder() {
        return DEFAULT_BUILDER;
    }

    /**
     * 序列化空字段
     *
     * @return
     */
    public static Gson builderSerializeNulls() {
        return SERIALIZE_NULL;
    }

    /**
     * 处理特殊的Double和Float
     * {@link Float#NaN},{@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}
     * <p>
     * {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}
     *
     * @return
     */
    public static Gson serializeSpecialFloatingPointValues() {
        return SERIALIZE_FLOATING_POINT;
    }

    /**
     * null字符串处理为""
     *
     * @return
     */
    public static Gson builderNullStringToBlack() {
        return NULL_STRING_TO_BLACK;
    }

    /**
     * 防止特殊符号进行unicode编码
     *
     * @return
     */
    public static Gson buildDisableHtmlEscaping() {
        return DISABLE_HTML_ESCAPING;
    }

    public static List<Long> parseListLongFromString(String str) {
        List<Long> longList = new ArrayList<>();
        if (StringUtils.isNotBlank(str)) {
            try {
                longList = GSON.fromJson(str, new TypeToken<ArrayList<Long>>() {
                }.getType());
            } catch (Exception e) {
                throw new RuntimeException("format error " + str);
            }
        }
        return longList;
    }

    public static List<Integer> parseListIntFromString(String str) {
        List<Integer> intList = new ArrayList<>();
        if (StringUtils.isNotBlank(str)) {
            try {
                intList = GSON.fromJson(str, new TypeToken<ArrayList<Integer>>() {
                }.getType());
            } catch (Exception e) {
                throw new RuntimeException("format error " + str);
            }
        }
        return intList;
    }

    public static List<String> parseListStringFromString(String str) {
        List<String> stringList = new ArrayList<>();
        if (StringUtils.isNotBlank(str) && !str.contains("[")) {
            stringList.add(str);
            return stringList;
        }
        if (StringUtils.isNoneBlank(str)) {
            try {
                stringList = GSON.fromJson(str, new TypeToken<ArrayList<String>>() {
                }.getType());
            } catch (Exception e) {
                throw new RuntimeException("format error " + str);
            }
        }
        return stringList;
    }

    static class NullStringToBlackAdapterFactory<T> implements TypeAdapterFactory {

        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
            Class<T> rawType = (Class<T>) typeToken.getRawType();
            if (rawType == String.class) {
                return (TypeAdapter<T>) new StringNullAdapter();
            }
            return null;
        }
    }

    static class StringNullAdapter extends TypeAdapter<String> {
        @Override
        public String read(JsonReader reader) throws IOException {
            if (reader.peek() == JsonToken.NULL) {
                reader.nextNull();
                return "";
            }
            return reader.nextString();
        }

        @Override
        public void write(JsonWriter writer, String value) throws IOException {
            if (value == null) {
                writer.value("");
                return;
            }
            writer.value(value);
        }
    }
}
